//
// Game.h
//

#pragma once

#include "DeviceResources.h"
#include "StepTimer.h"


// A basic game implementation that creates a D3D11 device and
// provides a game loop.
class Game : public DX::IDeviceNotify
{
public:

    Game();

    // Initialization and management
    void Initialize(HWND window, int width, int height);

    // Basic game loop
    void Tick();

    // IDeviceNotify
    virtual void OnDeviceLost() override;
    virtual void OnDeviceRestored() override;

    // Messages
    void OnActivated();
    void OnDeactivated();
    void OnSuspending();
    void OnResuming();
    void OnWindowMoved();
    void OnWindowSizeChanged(int width, int height);

    // Properties
    void GetDefaultSize(std::uint32_t& width, std::uint32_t& height) const;

private:

    void Update(DX::StepTimer const& timer);
    void Render();

    void Clear();

    void CreateDeviceDependentResources();
    void CreateWindowSizeDependentResources();

    void CompileCommonShaders(ID3D11Device* device);
    void CreateCommonVertexIndexBuffer(ID3D11Device* device);
    void ReadInputPicture(ID3D11Device* device);
    void CreateSampler(ID3D11Device* device);
    void CreateCommonResources(ID3D11Device* device);
    void RenderTex(ID3D11ShaderResourceView* source, ID3D11RenderTargetView* dest, ID3D11PixelShader* pixelShader, ID3D11DepthStencilView* strencil = nullptr);

    void InitGaussianBlurResources(ID3D11Device* device);
    void CompileKawaseShaders(ID3D11Device* device);

    //Blur impl
    void GaussianBlur(std::uint32_t count = 1);
    void GaussianBlurOpt(std::uint32_t count = 1);
    void KawaseBlur(std::uint32_t count = 5);

    // Device resources.
    std::unique_ptr<DX::DeviceResources>    m_deviceResources;

    // Rendering loop timer.
    DX::StepTimer                           m_timer;

    std::uint32_t                           m_windowWidth, m_windowHeight;

    //Common resources used by all blur algo.
    wrl::ComPtr<ID3D11Buffer>               m_vertexBuffer;
    wrl::ComPtr<ID3D11Buffer>               m_indexBuffer;
    wrl::ComPtr<ID3D11Texture2D>            m_orignalTex;
    wrl::ComPtr<ID3D11SamplerState>         m_sampler;
    wrl::ComPtr<ID3D11InputLayout>          m_inputLayout;
    wrl::ComPtr<ID3D11ShaderResourceView>   m_orignalTexView;
    wrl::ComPtr<ID3D11VertexShader>         m_commonVS;
    wrl::ComPtr<ID3D11Texture2D>            m_outputTex;
    wrl::ComPtr<ID3D11ShaderResourceView>   m_outputTexView;
    wrl::ComPtr<ID3D11PixelShader>          m_outputPS;

    wrl::ComPtr<ID3D11RenderTargetView>     m_tempRT;
    wrl::ComPtr<ID3D11RenderTargetView>     m_outputRT;
    std::uint32_t                           m_inputWidth, m_inputHeight;
    
    //shaders used in gaussian blur
    wrl::ComPtr<ID3D11PixelShader>          m_blurVertical;
    wrl::ComPtr<ID3D11PixelShader>          m_blurHorizonal;

    //optimized gaussian blur
    wrl::ComPtr<ID3D11PixelShader>          m_blurVerticalOpt;
    wrl::ComPtr<ID3D11PixelShader>          m_blurHorizonalOpt;

    //temp texture used in gaussian blur
    wrl::ComPtr<ID3D11Texture2D>            m_tempTex;
    wrl::ComPtr<ID3D11ShaderResourceView>   m_tempTexView;

    //naive gaussian blur
    wrl::ComPtr<ID3D11PixelShader>          m_naive;

    //shaders used in Kawase blur
    wrl::ComPtr<ID3D11PixelShader>          m_blurPasses[5];
};